#ifndef BLOCK_QUEUE_HPP
#define BLOCK_QUEUE_HPP

#include <pthread.h>
#include <unistd.h>

#include <iostream>
#include <queue>
template <class T>
class BlockQueue {
  static const int defaultnum = 10;

 public:
  BlockQueue(int maxcap = defaultnum) : maxcap_(maxcap) {
    pthread_mutex_init(&mutex_, nullptr);
    pthread_cond_init(&c_cond_, nullptr);
    pthread_cond_init(&p_cond_, nullptr);
    low_water_ = maxcap_ / 3;
    hight_water_ = maxcap_ * 2 / 3;
  }

  T pop() {  // 消费 Consumer
    pthread_mutex_lock(&mutex_);
    while (q_.size() == 0) {
      pthread_cond_wait(&c_cond_, &mutex_);
    }
    T out = q_.front();
    q_.pop();
    pthread_cond_signal(&p_cond_);

    pthread_mutex_unlock(&mutex_);

    return out;
  }

  void push(const T& in) {  // 生产 Productor
    pthread_mutex_lock(&mutex_); // 访问临界资源前进行上锁
    while (q_.size() == maxcap_) { // 进行条件判断 条件满足时
      pthread_cond_wait(&p_cond_, &mutex_);
    }
    q_.push(in);
    pthread_cond_signal(&c_cond_);

    pthread_mutex_unlock(&mutex_);
  }

  ~BlockQueue() {
    pthread_mutex_destroy(&mutex_);
    pthread_cond_destroy(&c_cond_);
    pthread_cond_destroy(&p_cond_);
  }

 private:
  std::queue<T> q_;  // 表示临界资源
  /* (STL容器不被保护 用户若是需要保护则需要自己上锁) */

  int maxcap_;  // 极值 当队列数据高于该值时生产者停止生产 通知消费者消费
  //   int mincap_;  // 极值 当队列数据低于该值时消费者停止消费 通知生产者生产

  pthread_mutex_t mutex_;  // 用于保护临界资源的互斥锁
  pthread_cond_t c_cond_;  // 条件变量
  pthread_cond_t p_cond_;

  int low_water_;    // 低水平位线
  int hight_water_;  // 高水平位线
  /*
    可通过加入水平位线条件控制生产者和消费者的生产消费策略
    如资源大于多少时通知消费者消费
    资源小于多少时通知生产者生产
   */
};
#endif
